package FileIO;

import java.io.File;
import java.io.FileInputStream;

import java.io.InputStream;
import java.util.ArrayList;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import Entities.Diet;
import Entities.LCAChain;
import Entities.Impact;
import Entities.Material;
import Entities.Process;

public class readXML{

	InputStream stream;
	XMLStreamReader reader;
	
	Diet diet = null;
	ArrayList<LCAChain> foods = null;
	ArrayList<Process> ps;
	ArrayList<Material> inputs;
	ArrayList<Material> outputs;
	ArrayList<Impact> impacts;
	LCAChain fc;
	Process p = null;
	Material m;
	Impact i;
	
	int enter = -1; //0-input 1-output

	
	public readXML(String SystemId) throws Exception{
		stream = new FileInputStream(SystemId);
		reader = XMLInputFactory.newInstance().createXMLStreamReader(SystemId, stream);
		diet = new Diet();
		foods = new ArrayList<LCAChain>();
	//	diet.setFoods(foods);
	}
	
	public ArrayList<LCAChain> parse() throws Exception{
		
		while(reader.hasNext()){

			if(reader.next() == XMLStreamReader.START_ELEMENT){
				parseElement();
			}
			
		}
		reader.close();
		stream.close();
		
		return foods;
	}
	
	private void parseList() throws Exception{
	
	//	while(reader.next() != XMLStreamReader.END_ELEMENT){
	//		if(reader.getEventType() != XMLStreamReader.START_ELEMENT)
	//			continue;
			parseElement();
	//	}
	}
	

	String attribute(String name){
		return reader.getAttributeValue(null,name);
	}
	
	private void parseElement() throws Exception{
	
		 if("Diet".equalsIgnoreCase(reader.getLocalName()))
		    parseDiet();
	     else if("Food".equalsIgnoreCase(reader.getLocalName()))
			parseFood();
		else if("Process".equalsIgnoreCase(reader.getLocalName()))
			parseProcess();
		else if("input".equalsIgnoreCase(reader.getLocalName()))
			parseInput();
		else if("output".equalsIgnoreCase(reader.getLocalName()))
			parseOutput();
		else if("evi_impact".equalsIgnoreCase(reader.getLocalName()))
			parseEvimpat();
		else if("material".equalsIgnoreCase(reader.getLocalName()))
			parseMaterial();
		else if("impact".equalsIgnoreCase(reader.getLocalName()))
			parseImpact();
		else{
			System.err.println("Unexpected element" + reader.getLocalName());
		}
		
	}
	

	private void parseDiet() throws Exception {
		// TODO Auto-generated method stub
		
		while(reader.hasNext()){
			reader.next();
			if(reader.getEventType() == XMLStreamReader.START_ELEMENT){
				if("Food".equalsIgnoreCase(reader.getLocalName())){
					parseList();
				}
				
			}if(reader.getEventType() == XMLStreamReader.END_ELEMENT){
				if("Diet".equalsIgnoreCase(reader.getLocalName())){
					return;
				}
			}
		}
	}

	private void parseFood() throws Exception {
		// TODO Auto-generated method stub
		
	    fc = new LCAChain();
		foods.add(fc);
		fc.setName(attribute("name"));
		fc.setType(attribute("type"));
		
		System.out.println("in this step: "+fc.getName()+ fc.getType() );
	    
		while(reader.hasNext()){
			reader.next();
			if(reader.getEventType() == XMLStreamReader.START_ELEMENT){
				if("Process".equalsIgnoreCase(reader.getLocalName())){
					if(fc.getProcesses() == null){
						fc.setProcesses(new ArrayList<Entities.Process>());
					}
					parseList();
				}
				
			}if(reader.getEventType() == XMLStreamReader.END_ELEMENT){
				if("Food".equalsIgnoreCase(reader.getLocalName())){
					return;
				}
			}
		}
		
		while(reader.next() != XMLStreamReader.END_ELEMENT ){
			if(reader.getEventType() == XMLStreamReader.START_ELEMENT){
				if("Process".equalsIgnoreCase(reader.getLocalName())){
					if(fc.getProcesses() == null){
						fc.setProcesses(new ArrayList<Entities.Process>());
						parseList();
					}
				}
			}
		}
	
	}
	
	private void parseProcess() throws Exception {
		// TODO Auto-generated method stub
		
		p = new Process();  
		fc.getProcesses().add(p);
		p.setType(this.attribute("p_name"));
		p.setDuration(Float.parseFloat(this.attribute("time")));
		p.setInfo(this.attribute("info"));
		
	    while(reader.hasNext()){
	
	    	reader.next();
	    	
	    	if(reader.getEventType() == XMLStreamReader.START_ELEMENT){
	    		if("input".equalsIgnoreCase(reader.getLocalName())){
	    			inputs = p.getInput();
	    			if(inputs == null){
	    				inputs = new ArrayList<Material>();
	    				p.setInput(inputs);
	    			}
	    			parseList();
	    			inputs = null;
	    		}
	    		else if("output".equalsIgnoreCase(reader.getLocalName())){
	    			outputs = p.getOuput();
	    			if(outputs == null){
	    				outputs = new ArrayList<Material>();
	    				p.setOutput(outputs);
	    			}
	    			parseList();
	    			outputs = null;
	    		}
	    		else if("impact".equalsIgnoreCase(reader.getLocalName())){
	    			impacts = p.getImpact();
	    			if(impacts == null){
	    				impacts = new ArrayList<Impact>();
	    				p.setImpact(impacts);
	    			}
	    			parseList();
	    			impacts = null;
	    		}
	    		else{
	    			System.out.println("Unexpected element " + reader.getLocalName());
	    		}
	    		
	    	}if(reader.getEventType() == XMLStreamReader.END_ELEMENT){
	    		if("Process".equalsIgnoreCase(reader.getLocalName()))
	    		{
	    			
	    			p = null;
	    			return;
	    		}
	    	}
	    }
	    
	    p = null;
		
	}

	private void parseImpact() throws  Exception {
		// TODO Auto-generated method stub
	while(reader.hasNext()){
			
			reader.next();
	    	if(reader.getEventType() == XMLStreamReader.START_ELEMENT){
	    		if("evi_impact".equalsIgnoreCase(reader.getLocalName())){
	 		
	    			parseList();
	    			
	    		}
	    	
	    	}else if(reader.getEventType() == XMLStreamReader.END_ELEMENT){
	    		if("impact".equalsIgnoreCase(reader.getLocalName()))
	    		{
	    			return;
	    		}
	    	}
		}
	}

	private void parseMaterial() {
		// TODO Auto-generated method stub
		Material m = new Material();
	 
	    m.setIsAdd(Integer.parseInt(this.attribute("isAdded")));
	    m.setName(this.attribute("name"));
	    m.setQuantity(Float.parseFloat(this.attribute("quantity")));
	    m.setUnit(this.attribute("unit"));
	    
	    if(enter ==0){
	    inputs.add(m);
	    }else if(enter == 1){
	    	outputs.add(m);
	    }
	}
	
	
	private void parseEvimpat() throws Exception {
		// TODO Auto-generated method stub
	    Impact i = new Impact();
	    impacts.add(i);
	    i.setName(this.attribute("name"));
	    i.setQuantity(Float.parseFloat(this.attribute("quantity")));
	    i.setType(this.attribute("type"));
	    i.setUnit(this.attribute("unit"));
	    
	}

	private void parseOutput() throws Exception {
		// TODO Auto-generated method stub
		
	while(reader.hasNext()){
			
			reader.next();
	    	if(reader.getEventType() == XMLStreamReader.START_ELEMENT){
	    		if("material".equalsIgnoreCase(reader.getLocalName())){
	    			enter = 1;
	    			parseList();
	    			enter = -1;
	    		}
	    	
	    	}else if(reader.getEventType() == XMLStreamReader.END_ELEMENT){
	    		if("output".equalsIgnoreCase(reader.getLocalName()))
	    		{
	    			return;
	    		}
	    	}
		}
		
	}

	private void parseInput() throws Exception {
		// TODO Auto-generated method stub
		
		while(reader.hasNext()){
			
			reader.next();
	    	if(reader.getEventType() == XMLStreamReader.START_ELEMENT){
	    		if("material".equalsIgnoreCase(reader.getLocalName())){
	    			enter = 0;
	    			parseList();
	    			enter = -1;
	    		}
	    	
	    	}else if(reader.getEventType() == XMLStreamReader.END_ELEMENT){
	    		if("input".equalsIgnoreCase(reader.getLocalName()))
	    		{
	    			return;
	    		}
	    	}
		}
		
	}
	
	public static boolean check(File file, Diet diet){
		readXML parse = null;
		try {
			parse = new readXML(file.getAbsolutePath());
			Diet t = new Diet();
			t.setFoods(parse.parse());
			
			return t.getFoods().equals(diet);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
		
	}

}